• Friday, September 27, 2024

    The content explores various lesser-known tricks, quirks, and features of the C programming language, aimed at both novice and experienced developers. It highlights aspects that can often confuse even seasoned programmers, presenting them in a casual, unordered format with brief explanations and examples. The discussion begins with the concept of array pointers, explaining how arrays decay to pointers and the implications of this behavior. It also touches on the comma operator, which allows multiple expressions to be evaluated in a single statement, emphasizing that only the last expression's value is returned. Next, the text introduces digraphs and trigraphs, which are alternative representations of certain characters in C, designed to enhance portability across different character encodings. The designated initializer feature is also covered, allowing developers to initialize specific elements of structures or arrays in any order, which can improve code clarity. Compound literals are discussed as a way to create unnamed objects with specific values, while also noting that they can be treated as lvalues, allowing their addresses to be taken. The concept of escaping shadowing is illustrated with an example that demonstrates how to access a variable from an outer scope. The content continues with multi-character constants, which are implementation-dependent and generally discouraged, but can serve as self-documenting enums. Bit fields are introduced as a means to define members of a structure with specific bit widths, and the use of zero-length bit fields is explained as a way to create boundaries between other bit fields. The volatile and restrict type qualifiers are discussed, highlighting their roles in informing the compiler about variable access and optimization opportunities. The register type qualifier is mentioned as a hint to the compiler to store variables in faster memory locations, although its relevance has diminished with modern compilers. Flexible array members are explained as a way to create dynamic arrays within structures, while the %n format specifier in printf is introduced as a means to retrieve the current output position. Other format specifiers are briefly mentioned, along with the concept of interlacing syntactic constructs, which can lead to unexpected behavior in code. The text also covers the use of the "operator" for decrementing and comparing values in a single expression, the syntactic sugar of array indexing, and the unconventional use of negative array indexes for debugging purposes. Constant string concatenation and backslash line splicing are presented as techniques for managing string literals in a more readable manner. Using logical operators as conditionals is highlighted, showcasing how they can be employed in a manner similar to shell scripting. Compile-time checks using enums are introduced as a way to enforce certain conditions during compilation. The content further explores ad hoc struct declarations, the peculiarities of nested struct definitions, and flat initializer lists. Implicit casting of void pointers is explained, along with the static array indices in function parameter declarations, which can aid in optimization. Macro overloading by argument list length is discussed, demonstrating how macros can be defined to handle different numbers of arguments. The text also delves into function types and the oddities surrounding function designators and pointers. X-macros are introduced as a powerful preprocessor technique, while named function parameters are presented as a way to enhance function calls with clarity. The combination of default, named, and positional arguments is explored, showcasing how to create flexible function interfaces. The use of unions for grouping related fields is discussed, along with the concept of unity builds, which can simplify the build process but may hinder modularization. Matching character classes with sscanf() is presented as a way to perform simple pattern matching. The content concludes with mentions of garbage collection libraries, the Cosmopolitan Libc project, inline assembly, and techniques for evaluating sizeof at compile time. It also touches on detecting constant expressions, object-oriented programming in C, and safe variadic functions. Metaprogramming and the capabilities of the C preprocessor are highlighted, emphasizing its complexity and potential for creative solutions. Overall, the text serves as a comprehensive exploration of C's intricacies, encouraging developers to delve deeper into the language's capabilities and nuances.

  • Wednesday, June 12, 2024

    A collection of programming essays on various topics, such as falsehoods programmers believe, choosing boring technology, becoming a more effective programmer, and more.

  • Friday, July 5, 2024

    The claim that learning C teaches you "how computers work" is inaccurate because C operates within its own abstract machine, not directly on the hardware. However, learning C can provide great insights into computer architecture and operating systems, as the C abstract machine closely maps to these elements. For programmers primarily using higher-level languages, learning C can be valuable to understanding how their code interacts with the underlying machine.

  • Thursday, July 18, 2024

    This developer, who completes Advent of Code in a new programming language every year, chose Zig for 2023 and found it to be a modernized C with a unique approach to error handling and type manipulation. Zig's standout features include detectable illegal behavior and comptime, which offer improved error detection and type-level programming capabilities respectively. However, Zig could benefit from enhancements in developer experience, including a better language server, clearer error messages, and improved documentation.

    Md Impact
  • Tuesday, July 30, 2024

    This article is a comprehensive guide on making C++ binaries highly debuggable, particularly for interactive debugging using tools like gdb. It focuses on configuring the C++ toolchain to produce binaries that are both efficient and easy to understand in the debugger. C++'s ahead-of-time compilation model requires a deliberate choice between debuggability and speed. The article presents various techniques, including enabling sanitizers, debug modes, and frame pointers to enhance the debugging experience.

  • Friday, September 20, 2024

    Bun 1.1.28 introduces experimental support for compiling and running native C code directly from JavaScript. This allows developers to utilize system libraries and APIs that are not directly accessible through JavaScript, overcoming the limitations of N-API and WebAssembly. This article goes over how Bun does it by using TinyCC for fast in-memory compilation that provides near-zero call overhead.

  • Wednesday, June 5, 2024

    The author of this thread wants to go lower level in development out of their own curiosity. Commenters recommend various paths, like CUDA programming, writing an OS kernel module, going deep into Android/iOS, working on game engines, and more.

  • Wednesday, May 22, 2024

    Although clever code feels impressive to write, it's often unmaintainable and unreasonable to write in production. Code that is easy to understand and readable is arguably harder to write than clever code. This article provides tips and resources for getting better at writing clear code, along with an anecdote about the difficulties of writing clear code and an email about coding style from John Carmack.

  • Tuesday, June 11, 2024

    This developer encountered a Pascal code snippet for disk parking at a young age but couldn't understand it. The code was filled with seemingly arbitrary numbers and letters and it frustrated the developer. Upon revisiting it decades later, the developer realized that the code was essentially just invoking a system call, using registers and arguments specific to the BIOS. It goes to show how experience and knowledge gained in the field can often be subtle but dramatic in approaching complex code and situations.

  • Monday, June 3, 2024

    Strong types in programming languages like C++ and Rust, which enforce specific data types and rules for variables, lead to fewer bugs, more expressive APIs, and potentially better performance. They prevent invalid input, improve code clarity, and reduce the need for repetitive error checking (like in JavaScript with undefined).

  • Wednesday, October 2, 2024

    In the exploration of programming languages and their longevity, Timm Murray reflects on the enduring presence of COBOL, a language his grandfather once declared "dead" in a 1992 article for Technical Support magazine. The article, filled with the jargon of its time, highlights the perception of COBOL as a relic, yet it has proven to be remarkably resilient, outlasting many other programming languages that were once considered more modern. Murray humorously suggests that COBOL might be more accurately described as a "zombie" language—something that is technically dead but continues to exist in some form. He draws a parallel to Autocoder, an earlier programming language that has largely faded from use but still has remnants in the computing landscape. This notion challenges the finality of the term "dead" when applied to programming languages, as many continue to linger in legacy systems, supported by a dwindling number of programmers. The Y2K problem is identified as a significant factor in COBOL's continued relevance. Despite the hype surrounding the potential crisis, it prompted a resurgence in the demand for COBOL programmers, ensuring that the language remained in use longer than anticipated. Murray notes that programming languages with a substantial historical user base rarely disappear completely; instead, they fade into obscurity, often without new generations of programmers to carry them forward. On a personal note, Murray shares the recent passing of his grandfather, who died at the age of 91. His grandfather's death, attributed to pneumonia, follows the loss of his grandmother earlier that year. This personal reflection adds a layer of poignancy to the discussion of legacy, both in programming and in family history, as he recalls the dry wit of his grandfather and the pride he felt in mirroring his humor. Through this narrative, Murray encapsulates the complexities of programming languages, the impact of technological evolution, and the personal connections that intertwine with these themes.

  • Thursday, October 3, 2024

    The blog post by Arne Bahlo expresses a growing appreciation for tools that function effectively without requiring extensive configuration. This sentiment is particularly relevant in the context of software development, where many tools demand significant setup time and effort. Bahlo highlights the contrast between customizable tools, like Emacs, and those that are ready to use right away, emphasizing the appeal of the latter. Bahlo begins by referencing Julia Evans' praise for the fish shell, which is designed to work without the need for configuration. The fish shell includes features such as autosuggestions by default, which are often reliant on plugins in other shells like ZSH. This ease of use is reflected in Bahlo's own minimal configuration for fish, which consists mainly of abbreviations and two plugins that require no additional setup. The discussion then shifts to Helix, a code editor that Bahlo has adopted after struggling with a complex Neovim configuration that involved multiple external plugins. Helix stands out for its built-in support for features like Language Server Protocol (LSP) and tree-sitter, which enhance coding efficiency without the need for extensive configuration. Bahlo shares his simple configuration for Helix, which consists of just a few lines of code, demonstrating how streamlined the setup process can be. Lazygit is another tool Bahlo praises for its user-friendly design, allowing for effective Git management without the need for configuration. He appreciates its intuitive interface and the ease with which users can navigate its features. Bahlo also mentions Zellij, a terminal multiplexer that offers a similar no-configuration experience. It allows users to create layouts and manage panes without additional plugins, with a standout feature being the ability to toggle floating panes, which enhances workflow. The post concludes with a call for readers to share their own zero or minimal configuration tools, fostering a community of developers who value simplicity and efficiency in their tools. Bahlo encourages developers to prioritize a seamless default experience in their creations, reflecting a broader trend towards user-friendly software solutions. Overall, the blog post serves as a celebration of tools that prioritize ease of use, highlighting how they can enhance productivity and reduce the friction often associated with software setup.

  • Wednesday, April 17, 2024

    Paper Code is a fast and performant C++ IDE.

  • Wednesday, June 12, 2024

    Clear, readable code is more valuable than clever code in the long run. This developer's experience at a large tech company revealed that even though clear code might seem trivial, it's actually more difficult to write and maintain. In order to “preserve complexity” for promotion packets, documentation was important for demonstrating the complexity of the work.

  • Wednesday, August 7, 2024

    This author built a simulated 8-bit computer from scratch in code to gain a better understanding of how CPUs work, specifically how bits move, how an ALU functions, and the basic fetch-decode-execute cycle.

  • Monday, August 19, 2024

    This developer expresses their fondness for Go but also lists features they miss from other languages. They find the lack of ordered maps in Go's standard library inconvenient, requiring developers to use third-party implementations or manually sort maps. The developer also misses keyword and default arguments for functions, which would simplify function calls and improve API design. They also wish there was lambda syntax in Go.

    Md Impact
  • Monday, September 30, 2024

    Writing code for computers presents its own set of challenges, but crafting code that humans will interact with is an even more complex endeavor. Erik Bernhardsson emphasizes the intricacies involved in creating frameworks, libraries, APIs, and programming languages that are not only functional but also user-friendly. The process requires a deep understanding of both computer science and the psychology of how users think and learn. To begin with, the onboarding experience is crucial. Bernhardsson argues that getting started with a product should be considered an integral part of the product itself, rather than an afterthought. He highlights the importance of minimizing friction in the setup process, suggesting that developers should aim to make it as easy as possible for users to start using their tools. This is particularly important in a landscape saturated with development tools, where users have limited patience and energy to explore new options. Humans learn best through examples rather than abstract concepts. Bernhardsson critiques the common practice of structuring documentation around core concepts, advocating instead for a focus on practical examples that allow users to see how the tool works in action. By providing a variety of examples, users can find a starting point that resonates with their specific needs, making the learning process more intuitive. The concept of "falling into the pit of success" is another key idea. Bernhardsson notes that users often encounter errors while programming, which can lead to frustration. Therefore, it is essential to design tools that guide users back to success quickly. This can be achieved by providing helpful error messages, code snippets in exceptions, and warnings that anticipate user mistakes. Avoiding conceptual overload is also vital. Each new concept that users must learn adds friction to their experience. Bernhardsson suggests that tools should aim to reduce the number of concepts users need to grasp while still allowing for a wide range of capabilities. He recalls his own experience with React, where a few simple concepts enabled him to build complex applications, illustrating the power of simplicity in design. The "conceptual duck principle" emphasizes the importance of using familiar terminology. By naming new features in a way that aligns with users' existing mental models, developers can significantly reduce the cognitive load required to understand new tools. This approach fosters a smoother learning curve and enhances user experience. Programmability is another critical aspect of user-friendly design. Bernhardsson encourages developers to create frameworks that allow users to manipulate and extend functionality easily. By enabling users to programmatically interact with the tool, developers can tap into users' creativity and encourage innovative uses of the framework. When it comes to defaults and magic in programming tools, Bernhardsson advises caution. While it may be tempting to minimize user input through defaults, this can lead to confusion if users are unaware of the underlying options. He argues for a balance between convenience and clarity, suggesting that tools should be designed to be intuitive without sacrificing the ability to customize. In conclusion, writing code for humans is a multifaceted challenge that requires careful consideration of user experience. Bernhardsson touches on various strategies to enhance developer tools, such as ensuring immutability, avoiding unnecessary scaffolding, and creating fast feedback loops. He reflects on the difficulty of designing for first-time users, likening it to producing a pop song where the creator must continually consider the perspective of a new listener. This complexity is part of what drives Bernhardsson's passion for building developer tools, as he seeks to create experiences that resonate with users and facilitate their success.

  • Tuesday, October 1, 2024

    The "Grug Brained Developer" presents a humorous and relatable perspective on software development, emphasizing the challenges faced by developers, particularly those who may not consider themselves highly skilled. The author, identifying as a "grug brain developer," shares insights gathered over years of experience, often highlighting the importance of simplicity and the dangers of complexity in coding. The introduction sets the tone, acknowledging that while the author may not be the smartest developer, there are valuable lessons learned from mistakes made throughout their career. The author expresses a desire to share these lessons in a way that is both entertaining and educational, particularly for younger developers who may be navigating similar challenges. A central theme is the concept of complexity, described as the "eternal enemy" of developers. The author argues that complexity is detrimental to codebases, often introduced by well-meaning but inexperienced developers. The struggle against this complexity is likened to battling a spirit demon that disrupts the clarity and functionality of code. The author humorously suggests that given a choice between facing a T-Rex or dealing with complexity, they would choose the dinosaur, as at least it is visible and understandable. To combat complexity, the author advocates for the power of saying "no." This includes resisting unnecessary features and abstractions that can complicate projects. While acknowledging that saying "yes" may be better for career advancement, the author emphasizes the importance of staying true to oneself and prioritizing simplicity over accolades. When compromise is necessary, the author suggests the "80/20 solution," where developers focus on delivering the most value with minimal code, thereby keeping complexity at bay. This approach often involves working without full disclosure to project managers, who may be overwhelmed and forgetful. The author also discusses the importance of properly factoring code, advising against premature abstraction. They emphasize the need to understand the system's shape before making significant changes, allowing for natural cut points to emerge in the codebase. This patience is contrasted with the tendencies of more experienced developers who may rush to create abstractions without fully grasping the project's needs. Testing is another critical area, where the author expresses a love/hate relationship. They advocate for writing tests after the initial prototype phase, emphasizing the importance of discipline in ensuring code works across different environments. The author prefers integration tests over unit tests, finding them more valuable for maintaining system stability. The discussion of agile methodologies reveals a cautious stance, recognizing that while agile can be beneficial, it can also lead to confusion and mismanagement if not implemented correctly. The author warns against the pitfalls of overly ambitious refactoring, suggesting that smaller, more manageable changes are often more successful. The text also touches on various programming concepts, such as type systems, expression complexity, and the balance between DRY (Don't Repeat Yourself) principles and simplicity. The author argues for a pragmatic approach to coding, where clarity and maintainability take precedence over strict adherence to theoretical ideals. In conclusion, the author reiterates the mantra that complexity is very bad, encapsulating the essence of their message. The "Grug Brained Developer" serves as both a guide and a humorous reflection on the realities of software development, encouraging developers to embrace simplicity, learn from mistakes, and navigate the complexities of coding with a sense of humor and humility.

  • Tuesday, September 10, 2024

    Design patterns make certain problems easier to deal with. Some patterns are easier to write in some languages than others. A language update to implement these patterns can make things easier for developers and produce cleaner code. This article presents an example of this where a new feature in Java made a particular design pattern a thing of the past.

    Md Impact
  • Friday, September 20, 2024

    The Safe C++ Extensions proposal, recently published by the C++ community, aims to address the challenge of ensuring that C++ code is free of memory safety bugs. Private and public sector organizations have been pushing programmers to write new applications and rewrite old ones in memory safe languages over the past two years. The majority of serious vulnerabilities in large codebases come from memory safety flaws. The Safe C++ project adds new technology for ensuring memory safety, preventing users from writing unsafe code. It allows existing code to work as always and ensures stakeholders have control for incrementally opting into safety.

    Hi Impact
  • Tuesday, May 28, 2024

    New CSS features are being introduced quickly, but developers are slow to adopt them. This is due to browser support concerns, lack of visible improvements, and the difficulty of adding new features to code with existing patterns. The best way to start using these better features is to experiment with them in low-cost environments (like side projects) and adopt them incrementally into your codebase.

  • Friday, August 30, 2024

    Python continues to lead IEEE Spectrum's 2024 programming language rankings, driven by its dominance in AI and education, while SQL remains highly sought after by employers. Rising stars include TypeScript and Rust, with the latter gaining attention for its memory safety features.

  • Tuesday, August 20, 2024

    This blog post discusses a novel technique for optimizing interpreter loops and protobuf parsing using tail calls in C. The author discovered that by utilizing the `[[clang::musttail]]` attribute, they got a huge performance boost, achieving protobuf parsing speeds exceeding 2 GB/s. The key benefit of tail calls is the elimination of function call overhead, resulting in more efficient control flow and reduced stack usage.

  • Monday, May 27, 2024

    Clever code is difficult to understand. “Clever code” can stem from valuing complex code over readability, premature abstraction, or over-adherence to the DRY (Don't Repeat Yourself) principle. Devs should instead try to write simple code that their future selves can easily understand.

  • Tuesday, October 1, 2024

    The article discusses the concept of "boring code" and its significance in software development, particularly in the context of mobile applications. The author, Jorge Coca, reflects on the qualities that make code effective and easy to work with, emphasizing that good code should be clear, predictable, and devoid of surprises. This perspective emerged from a conversation during a retrospective session where a team member described their codebase as "boring," which the author interpreted as a compliment. Coca argues that much of the functionality in mobile applications is repetitive, involving common tasks such as data fetching, transformation, and presentation. He suggests that producing "boring" code is beneficial because it minimizes unexpected issues, allowing engineering teams to focus on more complex business challenges rather than troubleshooting unforeseen problems. A well-structured codebase that is easy to navigate and well-tested contributes to this sense of predictability. To achieve this "boring" code, the author identifies two key components: creating super declarative and clear APIs, and ensuring that each piece of code is appropriately placed within the project structure. This involves distinguishing between data acquisition components, business rules, and presentation elements. By adhering to these principles, developers can create reusable components that streamline the development process across various applications. Coca concludes by expressing a commitment to sharing knowledge and best practices with the community, indicating plans to release a series of articles focused on transforming code into effective, "boring" code. This approach not only enhances efficiency but also fosters a more enjoyable development experience for teams.

  • Monday, March 11, 2024

    Google has published a whitepaper that outlines its "Secure by Design" approach, which advocates for the adoption of languages like Java, Go, and Rust to achieve high-assurance memory safety. Google has a massive C++ codebase. It will gradually adopt memory-safe languages for new code while seeking safety improvements for existing C++.

  • Monday, June 3, 2024

    Ivan Trusov, the lead programmer for a project, shares his experience using Lua for game development within the Defold engine. Trusov encountered some surprises with Lua's syntax and quirks, particularly with table handling. Despite these challenges, he found Lua's simplicity and speed very useful. Trusov also discusses the limitations of Lua's lack of strict typing and modules.

  • Monday, June 3, 2024

    A developer shares lessons learned from running a simple static news archive website for learning Finnish. He enjoys using cronjobs and Git together as they complement each other nicely. He also thinks simplicity and working locally are severely underrated.